var phongEffectVertexShaderStr = "\
attribute vec3 inPosition;\
attribute vec3 inNormal;\
attribute vec2 inTexCoord0;\
attribute float inObjIdx;\
uniform mat4 modelMat[25];\
uniform mat4 viewProjectionMat;\
uniform mat4 shadowMat;\
uniform vec3 viewPosition;\
varying vec3 outNormalInWorld;\
varying vec3 outViewVector;\
varying vec2 outTexCoord0;\
varying vec4 shadowCoord;\
void main(void)\
{\
  gl_Position = viewProjectionMat*modelMat[inObjIdx]*vec4(inPosition, 1.0);\
  shadowCoord = shadowMat*modelMat[inObjIdx]*vec4(inPosition,1.0);\
  shadowCoord.z-=0.005;\
  shadowCoord = vec4( shadowCoord.xyz/shadowCoord.w,shadowCoord.w);\
  outNormalInWorld = (modelMat[inObjIdx]*vec4(inNormal,0.0)).xyz;\
  vec4 posInWorld = modelMat[inObjIdx]*vec4(inPosition, 1.0);\
  outViewVector = viewPosition - vec3(posInWorld);\
  outTexCoord0 = inTexCoord0;\
}";
var phongEffectFragmentShaderStr = "\
varying vec3 outNormalInWorld;\
varying vec3 outViewVector;\
varying vec2 outTexCoord0;\
varying vec4 shadowCoord;\
uniform sampler2D texture0;\
uniform sampler2D shadowMap;\
uniform vec3 lightDir;\
uniform vec4 ambient;\
uniform vec4 diffuse;\
uniform vec4 specular;\
void main(void)\
{\
  vec4 texColor = texture2D(texture0,outTexCoord0);\
  if(texColor.a < ambient.a)\
    discard;\
  vec4 mapDepth = texture2D(shadowMap,shadowCoord.st);\
  float distanceFromLight = mapDepth.x + mapDepth.y/256.0+mapDepth.z/65536.0;\
  float shadow = 1.0;\
  if(shadowCoord.w > 0.0)\
      shadow = distanceFromLight < shadowCoord.z?diffuse.w:1.0 ;\
  vec3 N = normalize(outNormalInWorld);\
  vec3 V = normalize(outViewVector);\
  vec3 H = normalize(lightDir+V);\
  float _diffuse = max(dot(N,lightDir),0.0);\
  float _specular = _diffuse*pow(max(dot(N,H),0.0),specular.w);\
  vec3 ambientColor = ambient.rgb;\
  vec3 specularColor = _specular*specular.xyz;\
  vec3 diffuseColor = _diffuse*diffuse.xyz;\
  gl_FragColor =  vec4(ambientColor*texColor.rgb + (diffuseColor*texColor.rgb+specularColor)*shadow,1.0);\
}";
function gewPhongEffect(game)
{
  // General properties
  this.game = game;
  this.gl = game.gl;
  var gl = game.gl;
  this.name = "PhongEffect";
  this.scene3d = null;//Current scene3d that using this effect 
  this.materialList = {};
  this.currentPass = null;
   
  // Shader properties
  this.shader = {};
  createGLSLShader(gl,this.shader,phongEffectVertexShaderStr,phongEffectFragmentShaderStr); 
}
gewPhongEffect.prototype.destructor = function()
{
  var list  = this.materialList;
  var listLen = list.length;  
  for (var i in list)
  {
    list[i].destructor();
  }
  this.scene3d.removeEffect(this);
},
gewPhongEffect.prototype.render = function(scene3d) 
{
  var gl = this.gl; 
  this.scene3d = scene3d;
  var shader = this.shader;
  // push GL state
  // set GL state
  gl.useProgram(shader.program);
  gl.enableVertexAttribArray(shader.inPosition);
  gl.enableVertexAttribArray(shader.inNormal);
  gl.enableVertexAttribArray(shader.inTexCoord0);
  gl.enableVertexAttribArray(shader.inObjIdx);
  gl.enable(gl.DEPTH_TEST);
  gl.enable(gl.CULL_FACE);
  var light = scene3d.mainLight;
  var light_data = light.lightData;
  gl.uniform3f(shader.lightDir,light_data[0],light_data[1],light_data[2]);
  var shadowMat = light.shadowMat;
  gl.uniformMatrix4fv(shader.shadowMat, false, shadowMat.data);
  
  var viewProjMat = scene3d.viewProjectMat;
  gl.uniformMatrix4fv(shader.viewProjectionMat, false, viewProjMat.data);
  
  var viewPos = scene3d.viewPosition;
  gl.uniform3f(shader.viewPosition, viewPos.x, viewPos.y, viewPos.z);
  // render pass 0 with all material
  this.currentPass = 0;
  var materialList = this.materialList;
  var listLen = materialList.length;
  for(var i in materialList)
  { 
    materialList[i].render();
  }
  //
  gl.currentPass = null;
  // pop GL state  
  gl.disable(gl.DEPTH_TEST);
  gl.disable(gl.CULL_FACE);
  gl.disableVertexAttribArray(shader.inPosition);
  gl.disableVertexAttribArray(shader.inNormal);
  gl.disableVertexAttribArray(shader.inTexCoord0);
  gl.disableVertexAttribArray(shader.inObjIdx);
}
